package br.com.sovi.socket.mina;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.log4j.Logger;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;

@Component
public class ServerSupport extends IoHandlerAdapter implements DisposableBean {

	private final Logger logger = Logger.getLogger(getClass());

	private IoSession session;

	private SocketAcceptor acceptor;
	
	public ServerSupport() {
		startAcceptor();
	}

	private void startAcceptor() {
		acceptor = new SocketAcceptor();

		try {
			// config.getFilterChain().addLast("logger", new LoggingFilter() );
			acceptor.getFilterChain().addLast("codec",
					new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

			acceptor.bind(new InetSocketAddress(2009), this);

			logger.debug("Acceptor iniciado com sucesso.");
		}
		catch (Exception e) {
			logger.error("Erro ao abrir socket de conexão.", e);
		}

	}

	public void sendMessage(String message) throws IllegalArgumentException {
		if (session != null) {
			session.write(message);
		}
		else {
			throw new IllegalArgumentException("Não foi possível conectar ao servidor da bandeira: ");
		}
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		logger.error("Erro", cause);
		session.close();
	}

	@Override
	public void messageReceived(IoSession session, Object message) throws Exception {
		this.session = session;

		logger.debug("Recebendo mensagem.");
		try {
			String received = null;

			if (message instanceof ByteBuffer) {
				ByteBuffer buffer = (ByteBuffer) message;
				buffer.flip();
				received = new String(buffer.array());
				buffer.clear();
			}
			else {
				received = message.toString();
			}

			logger.info("Mensagem recebida: " + received);

			// TODO tratar o received
			
			sendMessage("sovi.recebido=" + received);
		}
		catch (Exception e) {
			throw new IllegalArgumentException("Ocorreu um erro ao receber uma nova mensagem.", e);
		}
	}

	public void close() {
		if (session != null) {
			if (session.isConnected()) {
				session.getCloseFuture().join();
			}
			session.close();
		}
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
		logger.debug("Enviando: " + message.toString());
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		logger.debug("Session Closed! ");
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		logger.debug("Session Created!");
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception {
		logger.debug("Session Opened!");
	}

	public void destroy() throws Exception {
		close();
	}

}
